﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AgvDispatchSystem
{
    public class SerialPortDriver : IDriver
    {
        private short _id;
        private string _name;
        private AutoResetEvent resetEvent = null;                 // 消息同步机制
        private byte[] buffer = null;                             // 接收缓冲区
        private int receiveCount = 0;                             // 接收的数据长度
        private SerialPort _serialPort;                           // 串口交互的核心
        private SimpleHybirdLock hybirdLock;                      // 数据交互的锁
        private ILogNet logNet;                                   // 日志存储
        private int receiveTimeout = 5000;                        // 接收数据的超时时间
        private bool isReceiveTimeout = false;                    // 是否接收数据超时
        private bool isReceiveComplete = false;                   // 是否接收数据完成

        public short DriverID {get => _id; } 

        public string Name { get => _name; }

        [Category("串口设置"), Description("串口号")]
        public string PortName { get; set; } = "COM1";

        public string ServerName { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }

        public bool IsClosed { get => _serialPort == null || !_serialPort.IsOpen; }

        [Category("串口设置"), Description("通迅超时时间")]
        public int TimeOut { get; set; } = 3000;

        [Category("串口设置"), Description("波特率")]
        public int BaudRate { get; set; } = 9600;

        [Category("串口设置"), Description("数据位")]
        public int DataBits { get; set; } = 8;

        [Category("串口设置"), Description("停止位")]
        public StopBits StopBits { get; set; } = StopBits.One;

        [Category("串口设置"), Description("奇偶校验")]
        public Parity Parity { get; set; } = Parity.None;

        public SerialPortDriver()
        {
            resetEvent = new AutoResetEvent(false);
            buffer = new byte[2048];
            hybirdLock = new SimpleHybirdLock();
        }

        /// <summary>
        /// 接收数据的超时时间
        /// </summary>
        public int ReceiveTimeout
        {
            get { return receiveTimeout; }
            set { receiveTimeout = value; }
        }

        public event IOErrorEventHandler OnError;

        public bool Connect()
        {
            try
            {
                if (TimeOut <= 0) TimeOut = 1000;
                if (_serialPort == null)
                    _serialPort = new SerialPort(PortName);
                _serialPort.ReadTimeout = TimeOut;
                _serialPort.WriteTimeout = TimeOut;
                _serialPort.BaudRate = BaudRate;
                _serialPort.DataBits = DataBits;
                _serialPort.Parity = Parity;
                _serialPort.StopBits = StopBits;
                _serialPort.Open();
                _serialPort.DataReceived += SP_ReadData_DataReceived;
                return true;
            }
            catch (IOException error)
            {
                OnError?.Invoke(this, new IOErrorEventArgs(error.Message));
                return false;
            }
        }

        public byte[] WriteAndRead(byte[] value)
        {
            byte[] result = null;

            hybirdLock.Enter();

            try
            {
                isReceiveTimeout = false;                         // 是否接收超时的标志位
                isReceiveComplete = false;                        // 是否接收完成的标志位
                if (value == null) value = new byte[0];

                _serialPort.Write(value, 0, value.Length);
                ThreadPool.QueueUserWorkItem(new WaitCallback(CheckReceiveTimeout), null);
                resetEvent.WaitOne();
                isReceiveComplete = true;

                if (isReceiveTimeout)
                {
                    result = null;
                }
                else
                {
                    byte[] tmp = new byte[receiveCount];
                    Array.Copy(buffer, 0, tmp, 0, tmp.Length);

                    result = tmp;
                }
            }
            catch (Exception ex)
            {
                logNet?.WriteException(ToString(), ex);
            }
            finally
            {
                hybirdLock.Leave();
            }

            receiveCount = 0;
            return result;
        }

        private void CheckReceiveTimeout(object obj)
        {
            int receiveTimes = 0;
            while (!isReceiveComplete)
            {
                Thread.Sleep(100);
                receiveTimes += 100;

                if (receiveTimes >= receiveTimeout)
                {
                    if (!isReceiveComplete)
                    {
                        // 超时退出
                        isReceiveTimeout = true;
                        resetEvent.Set();
                        break;
                    }
                }
            }
        }

        private void SP_ReadData_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            while (true)
            {
                Thread.Sleep(20);
                if (_serialPort.BytesToRead < 1) break;

                // 继续接收数据
                receiveCount += _serialPort.Read(buffer, receiveCount, _serialPort.BytesToRead);
            }
            resetEvent.Set();
        }
    }
}
